/*********************************
 * jsmud: JavaScript MUD Kernel  *
 *          Mojodo, Inc.         *
 *        Sean Middleditch       *
 * Copyright (C) 2005,2007,2008  *
 *      All rights reserved.     *
 *   See COPYING for licensing.  *
 *********************************/

/* ==== SYSTEM INCLUDES ==== */

#include <string.h>
#include <errno.h>
#include <limits.h>
#include <arpa/telnet.h>
#include <sys/stat.h>

/* ==== LIBRARY INCLUDES ==== */

#include <sqlite3.h>
#include <zlib.h>

#define XP_UNIX 1
#define MOZILLA_1_8_BRANCH 1
#include <jsapi.h>
#undef XP_UNIX
#undef MOZILLA_1_8_BRANCH

/* ==== JSMUD HEADER ==== */

#include "jsmud.h"

/* ==== DECLARATIONS ==== */

JSAPI(js_db_exec);
JSAPI(js_db_query);

JSAPI(js_resultset_next);
JSAPI(js_resultset_nextarray);
static void js_resultset_finalize (JSContext* cx, JSObject* self);

/* ==== SCRIPT BINDINGS - DB ==== */

static JSFunctionSpec js_db_functions[] = {
	{"exec", js_db_exec, 1, 0, 0},
	{"query", js_db_query, 1, 0, 0},
	{NULL, 0, 0, 0, 0}
};

JSClass js_resultset_class = {
	"ResultSet", JSCLASS_HAS_PRIVATE,
	JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,
	JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,js_resultset_finalize,
	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL
};
JSObject* js_resultset_prototype;

static JSFunctionSpec js_resultset_methods[] = {
	{"next", js_resultset_next, 1, 0, 0},
	{"nextArray", js_resultset_nextarray, 1, 0, 0},
	{NULL, 0, 0, 0, 0}
};

JSAPI(js_db_exec)
{
	JSString* string;
	const char* sql;
	sqlite3_stmt* stmt;

	if ((string = JS_ValueToString(cx, argv[0])) == NULL)
		return JS_FALSE;
	sql = JS_GetStringBytes(string);

	stmt = db_prepare(sql, argc - 1, &argv[1]);
	if (stmt == NULL)
		return JS_FALSE;

	sqlite3_step(stmt);
	sqlite3_finalize(stmt);

	return JS_TRUE;
}

JSAPI(js_db_query)
{
	JSString* string;
	sqlite3_stmt* stmt;
	JSObject* result;
	const char* sql;

	if ((string = JS_ValueToString(cx, argv[0])) == NULL)
		return JS_FALSE;
	sql = JS_GetStringBytes(string);

	if ((result = JS_NewObject(cx, &js_resultset_class, js_resultset_prototype, NULL)) == NULL)
		return JS_FALSE;
	*rval = OBJECT_TO_JSVAL(result);

	stmt = db_prepare(sql, argc - 1, &argv[1]);
	if (stmt == NULL)
		return JS_FALSE;

	JS_SetPrivate(cx, result, stmt);

	return JS_TRUE;
}

JSAPI(js_resultset_next)
{
	sqlite3_stmt* stmt;

	stmt = (sqlite3_stmt*)JS_GetPrivate(cx, self);
	if (stmt == NULL) {
		*rval = JSVAL_NULL;
		return JS_TRUE;
	}

	if (db_get_result(stmt, rval) == JS_FALSE) {
		*rval = JSVAL_NULL;
		sqlite3_finalize(stmt);
		JS_SetPrivate(cx, self, NULL);
		return JS_TRUE;
	}

	return JS_TRUE;
}

JSAPI(js_resultset_nextarray)
{
	sqlite3_stmt* stmt;

	stmt = (sqlite3_stmt*)JS_GetPrivate(cx, self);
	if (stmt == NULL) {
		*rval = JSVAL_NULL;
		return JS_TRUE;
	}

	if (db_get_result_array(stmt, rval) == JS_FALSE) {
		*rval = JSVAL_NULL;
		sqlite3_finalize(stmt);
		JS_SetPrivate(cx, self, NULL);
		return JS_TRUE;
	}

	return JS_TRUE;
}

static void js_resultset_finalize (JSContext* cx, JSObject* self)
{
	sqlite3_stmt* stmt = (sqlite3_stmt*)JS_GetInstancePrivate(cx, self, &js_resultset_class, NULL);
	if (stmt != NULL)
		sqlite3_finalize(stmt);
}

/* ==== INITIALIZE BINDINGS ==== */

int init_dblib (void)
{
	JSObject* ns_db;

	/* create "namespace" object */
	if ((ns_db = JS_DefineObject(js_context, js_global, "DB", NULL, NULL, JSPROP_ENUMERATE|JSPROP_PERMANENT)) == NULL) {
		log_error("JS_DefineObject() failed");
		return 0;
	}

	/* create all our custom functions */
	if (!JS_DefineFunctions(js_context, ns_db, js_db_functions)) {
		log_error("JS_DefineFunctions() failed");
		return 0;
	}

	/* create our database result set class */
	if ((js_resultset_prototype = JS_InitClass(js_context, ns_db, NULL, &js_resultset_class, NULL, 0, NULL, js_resultset_methods, NULL, NULL)) == NULL) {
		log_error("JS_InitClass() failed");
		return 0;
	}
	JS_AddRoot(js_context, &js_resultset_prototype);

	return 1;
}

/* vim: set tabstop=2 shiftwidth=2 ai: */
